package org.jslaughter.component.physics.motion;

import org.jslaughter.event.eventtype.MotionEvent;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Input;
import org.nvframe.component.AbstractComponent;
import org.nvframe.component.physics.state.PhysicsPosition;
import org.nvframe.component.render.MultipleImageRender;
import org.nvframe.entity.Entity;
import org.nvframe.event.EventService;
import org.nvframe.event.eventtype.UpdateEvent;
import org.nvframe.event.eventtype.UpdateListener;
import org.nvframe.manager.InputManager;
import org.nvframe.util.settings.SettingsObj;

/**
 * 
 * @author Nik Van Looy
 */
public class TopDownMotion extends AbstractComponent implements UpdateListener {

	private float stepSpeed;
	private float rotSpeed;
	private String multipleRenderTarget;

	public TopDownMotion(String id, Entity owner, SettingsObj settings) {
		super(id, owner);
		
		multipleRenderTarget = settings.getString("multipleRenderTarget");
		
		stepSpeed = settings.getFloat("stepSpeed");
		rotSpeed = settings.getFloat("rotSpeed");
		
		EventService.getInstance().addEventListener(this);
	}

	private float calculateDirection(float currentDir, float destDir, int delta) {
		boolean clockwise = true;
		
		currentDir = currentDir % 360 < 0 ? 360 - Math.abs(currentDir % 360) : Math.abs(currentDir % 360);

		if(Math.abs(currentDir - destDir) <= rotSpeed)
			return currentDir;
		
		clockwise = destDir - currentDir < 0 ? false : true;
		
		if(Math.abs(destDir - currentDir) > 180)
			clockwise = !clockwise;
		
		if(clockwise)
			return currentDir + rotSpeed * delta;
		else
			return currentDir - rotSpeed * delta;
	}
	
	private float getRotationDest(Input input, float currRot) {
		InputManager inputManager = InputManager.getInstance();
		
		if(input.isKeyDown(inputManager.getInput("player_motion_up")) && input.isKeyDown(inputManager.getInput("player_motion_right")))
			return 315;
		if(input.isKeyDown(inputManager.getInput("player_motion_right")) && input.isKeyDown(inputManager.getInput("player_motion_down")))
			return 45;
		if(input.isKeyDown(inputManager.getInput("player_motion_down")) && input.isKeyDown(inputManager.getInput("player_motion_left")))
			return 135;
		if(input.isKeyDown(inputManager.getInput("player_motion_left")) && input.isKeyDown(inputManager.getInput("player_motion_up")))
			return 225;
		if(input.isKeyDown(inputManager.getInput("player_motion_up")))
			return 270;
		if(input.isKeyDown(inputManager.getInput("player_motion_right")))
			return 0;
		if(input.isKeyDown(inputManager.getInput("player_motion_down")))
			return 90;
		if(input.isKeyDown(inputManager.getInput("player_motion_left")))
			return 180;
		
		return currRot;
	}

	public void onUpdate(UpdateEvent event) {
		GameContainer gc = event.getGc();
		int delta = event.getDelta();
		InputManager inputManager = InputManager.getInstance();

		Input input = gc.getInput();
		MultipleImageRender targetComponent = (MultipleImageRender) owner.getComponent(MultipleImageRender.class);
		PhysicsPosition position = (PhysicsPosition) owner.getComponent(PhysicsPosition.class);
		float direction = targetComponent.getDirection(multipleRenderTarget);
		float destDir = getRotationDest(input, direction);
		
		if(position == null)
			return;
		
		direction = calculateDirection(direction, destDir, delta);
		
		boolean motion = false;
		
		float stepSpeed = this.stepSpeed;
		
		if(input.isKeyDown(inputManager.getInput("player_motion_run")))
			stepSpeed *= 2;
		
		if(input.isKeyDown(inputManager.getInput("player_motion_up"))) {
			motion = true;
			//position.adjustVelocity(position.getVelocity().x, -stepSpeed * delta);
			position.applyForce(0, -stepSpeed * delta);
		}
		if(input.isKeyDown(inputManager.getInput("player_motion_right"))) {
			motion = true;
			//position.adjustVelocity(stepSpeed * delta, position.getVelocity().y);
			position.applyForce(stepSpeed * delta, 0);
		}
		if(input.isKeyDown(inputManager.getInput("player_motion_down"))) {
			motion = true;
			//position.adjustVelocity(position.getVelocity().x, stepSpeed * delta);
			position.applyForce(0, stepSpeed * delta);
		}
		if(input.isKeyDown(inputManager.getInput("player_motion_left"))) {
			motion = true;
			//position.adjustVelocity(-stepSpeed * delta, position.getVelocity().y);
			position.applyForce(-stepSpeed * delta, 0);
		}
		
		// fire motion event when object is moving
		if(motion)
			EventService.getInstance().fireEvent(new MotionEvent(getOwner()));

		targetComponent.setDirection(multipleRenderTarget, direction);
		//position.setDirection(direction);
	}
	
}